#include "stdafx.h"
#include "ylSymbolLookup.h"


#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <dbghelp.h>

using namespace yoctolog_viewer;


SymbolLookup *SymbolLookup::ms_pInstance = NULL;


SymbolLookup::SymbolLookup()
	: m_hCurrentProcess(0)
{

}


SymbolLookup::~SymbolLookup()
{
	CleanUp();
}


void SymbolLookup::CleanUp()
{
	// Cleanup
	if( m_hCurrentProcess != 0 )
	{
		SymCleanup((HANDLE)m_hCurrentProcess);
		m_hCurrentProcess = 0;
	}
}


void SymbolLookup::InitForProcess(unsigned int uiProcess)
{
	if( m_hCurrentProcess == uiProcess )
		return;

	CleanUp();

	HANDLE hProcess = (HANDLE)uiProcess;

	SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_ANYTHING | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_LOAD_LINES);
	if( !SymInitialize(hProcess, 0, TRUE) )
	{
		return;
	}

/*
	DWORD64 dwBaseAddr = 0;

	if (SymLoadModuleEx(hProcess,    // target process 
		NULL,        // handle to image - not used
		"imagefile.exe", // name of image file
		NULL,        // name of module - not required
		dwBaseAddr,  // base address - not required
		0,           // size of image - not required
		NULL,        // MODLOAD_DATA used for special cases 
		0))          // flags - not required
	{
		// SymLoadModuleEx returned success
	}
	else
	{
		// SymLoadModuleEx failed
		DWORD error = GetLastError();
		printf("SymLoadModuleEx returned error : %d\n", error);
	}
*/

	m_hCurrentProcess = uiProcess;
}


std::string SymbolLookup::GetSymbolFromAddr(unsigned int uiProcess, unsigned int iAddr)
{
	if( m_hCurrentProcess == 0 || m_hCurrentProcess != uiProcess )
		InitForProcess(uiProcess);

	HANDLE hProcess = (HANDLE)uiProcess;

	char pSymbolData[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
	SYMBOL_INFO *sym = reinterpret_cast<SYMBOL_INFO *>(&pSymbolData[0]);
	sym->MaxNameLen = MAX_SYM_NAME;
	sym->SizeOfStruct = sizeof(SYMBOL_INFO);

	HRESULT hr = SymFromAddr(hProcess, (DWORD64)iAddr, 0, sym);
	if( hr == TRUE )
	{
		std::string strSym = sym->Name;
		return strSym;
	}
	else
	{
		DWORD dwErr = GetLastError();

		return "FAIL.";
	}
}


void SymbolLookup::GetLineNumberFromAddr(unsigned int uiProcess, unsigned int iAddr, std::string &strFilename, int &iLineNumber)
{
	if( m_hCurrentProcess == 0 || m_hCurrentProcess != uiProcess )
		InitForProcess(uiProcess);

	DWORD64  dwAddress = iAddr;
	DWORD  dwDisplacement = 0;
	IMAGEHLP_LINE64 line;

	line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

	if (SymGetLineFromAddr64((HANDLE)uiProcess, dwAddress, &dwDisplacement, &line))
	{
		// SymGetLineFromAddr64 returned success
		strFilename = line.FileName;
		iLineNumber = line.LineNumber;
	}
	else
	{
		// SymGetLineFromAddr64 failed
		DWORD error = GetLastError();
		//_tprintf(TEXT("SymGetLineFromAddr64 returned error : %d\n"), error);
	}


}